package cn.sjx.modules.nbiot.entity.send;

import cn.sjx.modules.nbiot.entity.common.IotProtocolConstants;
import cn.sjx.modules.nbiot.util.CRC16Util;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Data;
import lombok.experimental.Accessors;

/**
 * 报文数据发送基类
 *
 * @Author: sjx
 * @Date: 2019年08月31日 0031 14:11:55
 */
@Data
@Accessors(chain = true)
public abstract class IotProtocolSendBase {

    /**
     * <p>
     * 字段名称：协议头部
     * 说明：协议头
     * 字节：1
     * </p>
     */
    protected int head;

    /**
     * <p>
     * 字段名称：校验码
     * 说明：CRC16
     * 字节：2
     * </p>
     */
    protected short crcCode;

    // region ================================= 扩展字段 =================================

    protected int msgBodyLength;

    // end region ============================= 扩展字段 =================================

    /**
     * 默认构造函数
     */
    public IotProtocolSendBase() {
    }

    /**
     * 设置协议头
     *
     * @param head
     */
    public IotProtocolSendBase(int head) {
        this.head = head;
    }

    /**
     * 发送数据编码
     */
    public byte[] encode() {

        // 创建数据包
        ByteBuf buf = Unpooled.buffer(IotProtocolConstants.MSG_FIX_LENGTH + msgBodyLength);

        // 写协议头
        buf.writeByte(getHead());

        // 写数据体
        encodeImpl(buf);

        // 写校验码
        ByteBuf copyBuf = Unpooled.copiedBuffer(buf);
        byte[] b = Unpooled.buffer(copyBuf.readableBytes()).array();
        copyBuf.getBytes(0, b);
        byte[] crcCodeByte = CRC16Util.getCrc16(b);
        buf.writeBytes(crcCodeByte);

        // 赋值
        setCrcCode(byteToShort(crcCodeByte));

        return buf.array();
    }

    protected abstract void encodeImpl(ByteBuf buf);

    /**
     * 补全位数不够的定长参数 有些定长参数，实际值长度不够，在后面补0x00
     *
     * @param length
     * @param writeByte
     * @return
     */
    protected byte[] getBytesWithLengthAfter(int length, byte[] writeByte) {
        byte[] lengthByte = new byte[length];
        for (int i = 0; i < writeByte.length; i++) {
            lengthByte[i] = writeByte[i];
        }
        for (int i = 0; i < (length - writeByte.length); i++) {
            lengthByte[writeByte.length + i] = 0x00;
        }
        return lengthByte;
    }

    /**
     * 字节数组到short的转换！
     *
     * @param b
     * @return
     */
    protected static short byteToShort(byte[] b) {
        short s = 0;
        // 最低位
        short s0 = (short) (b[0] & 0xff);
        short s1 = (short) (b[1] & 0xff);
        s1 <<= 8;
        s = (short) (s0 | s1);
        return s;
    }
}
